package tcln.gxtx.client.utils.store;

import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.store.Record;
import com.extjs.gxt.ui.client.store.Store;

/**
 * An "optimizable" record updater implementation. The 'optimizable' feature here depends on input store. In particular,
 * if the input store passed to this updater is an {@link ExtendedTreeStore}, then the following optimization is
 * applied:
 * <ul>
 * <li>On {@link #updateRecord(com.extjs.gxt.ui.client.store.Store, ModelData, String, Object)}, changes are cached
 * locally in this updater.
 * <li>Then, when method {@link #finishUpdating(com.extjs.gxt.ui.client.store.Store)} is invoked, all changes are
 * updated to corresponding records of all modified models. Immediate refresh of modified rows ARE NOT performed until
 * all changes for a model are updated to this model's record.
 * <li>Commission of records' changes is the same as the default implementation.
 * </ul>
 * 
 * @param <M>
 *            model data type.
 * @author Truong Chau Lien Ngoc (lienngoc@gmail.com)
 */
public class OptimizableRecordUpdater<M extends ModelData> extends DefaultRecordUpdater<M> {

    OptimizableRecordUpdater() {
        // to hide
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setStore(Store<M> store) {
        super.setStore(store);

        // warn developer about this mistake so that he/she may be noticed.
        if (!isOptimizableStore()) {
            System.out.println("Warning: No optimized store was found (Should be ExtendedTreeStore or subclasses)"
                    + " => This updater acts as the DefaultRecordUpdater");
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void finishUpdating() {
        if (isOptimizableStore()) {

            // enable 'afterEdit' to update page layout and DOM
            ExtendedTreeStore<M> optzStore = getOptimizableStore();
            optzStore.setAfterEditDisabled(false);

            // manually invoke 'afterEdit'
            for (M m : this.modifiedModels) {
                Record record = ownerStore.getRecord(m);
                optzStore.afterEdit(record);
            }
        }

        super.finishUpdating();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void updateRecord(M modifiedModel, String property, Object newValue) {

        // disable 'afterEdit' call for each Record.set
        if (isOptimizableStore()) {
            getOptimizableStore().setAfterEditDisabled(true);
        }

        super.updateRecord(modifiedModel, property, newValue);
    }

    private boolean isOptimizableStore() {
        return ownerStore instanceof ExtendedTreeStore<?>;
    }

    private ExtendedTreeStore<M> getOptimizableStore() {
        return (ExtendedTreeStore<M>) ownerStore;
    }
}
